var _ctCsvMdLast = { rows: [], aligns: [], header: true }; function _ctParseDelimited(text, delim) { var rows = []; var row = []; var field = ''; var inQuotes = false; var s = text; var i = 0; while (i < s.length) { var c = s.charAt(i); if (inQuotes) { if (c === '\"' && s.charAt(i+1) === '\"') { field += '\"'; i += 2; continue; } if (c === '\"') { inQuotes = false; i++; continue; } field += c; i++; continue; } if (c === '\"' && field.trim() === '') { field = ''; inQuotes = true; i++; continue; } if (c === delim) { row.push(field); field = ''; i++; continue; } if (c === '\n') { row.push(field); rows.push(row); row = []; field = ''; i++; continue; } field += c; i++; } if (field !== '' || row.length) { row.push(field); rows.push(row); } return rows; } // Pick the delimiter that splits the first few lines into the most consistent number of columns. function _ctDetectDelimiter(text) { var lines = text.split('\n').filter(function(l){ return l.trim() !== ''; }).slice(0, 20); var candidates = ['\t', ',', ';', '|']; var best = ',', bestScore = 0; candidates.forEach(function(d){ var counts = lines.map(function(l){ var n = 0, q = false; for (var i = 0; i < l.length; i++) { var c = l.charAt(i); if (c === '\"') q = !q; else if (c === d && !q) n++; } return n; }); if (!counts.length || counts[0] === 0) return; var same = counts.filter(function(n){ return n === counts[0]; }).length; var score = (same / counts.length) * 100 + counts[0]; if (score > bestScore) { bestScore = score; best = d; } }); return best; } function _ctCellWidth(s) { var w = 0; for (var ch of s) { var cp = ch.codePointAt(0); if (cp >= 0x300 && cp <= 0x36f) continue; if (cp === 0x200d || (cp >= 0xfe00 && cp <= 0xfe0f)) continue; w += ((cp >= 0x1100 && cp <= 0x115f) || (cp >= 0x2e80 && cp <= 0xa4cf) || (cp >= 0xac00 && cp <= 0xd7a3) || (cp >= 0xf900 && cp <= 0xfaff) || (cp >= 0xfe30 && cp <= 0xfe4f) || (cp >= 0xff00 && cp <= 0xff60) || (cp >= 0xffe0 && cp <= 0xffe6) || (cp >= 0x1f300 && cp <= 0x1faff) || (cp >= 0x20000 && cp <= 0x3fffd)) ? 2 : 1; } return w; } function _ctMdEscape(cell) { return String(cell == null ? '' : cell) .replace(/\|/g, '\\|') .replace(/\n/g, '
'); } function _ctIsNumber(s) { return /^[-+(]?[$€£¥]?\s?\d[\d,\s]*(\.\d+)?\)?\s?%?$/.test(s) || /^[-+]?\.\d+%?$/.test(s); } function _ctOpt(id, fallback) { var el = document.getElementById(id); if (!el) return fallback; return el.type === 'checkbox' ? el.checked : el.value; } function convert(input) { var text = (input || '').replace(/^/, '').replace(/\r\n/g, '\n').replace(/\r/g, '\n'); var status = document.getElementById('csvmd-status'); var delimChoice = _ctOpt('csvmd-delim', 'auto'); var delim = delimChoice === 'auto' ? _ctDetectDelimiter(text) : (delimChoice === 'tab' ? '\t' : delimChoice); var header = _ctOpt('csvmd-header', true); var align = _ctOpt('csvmd-align', 'auto'); var pad = _ctOpt('csvmd-pad', true); var trim = _ctOpt('csvmd-trim', true); var rows = _ctParseDelimited(text, delim).filter(function(r){ return r.some(function(c){ return c.trim() !== ''; }); }); // A pasted Markdown-style table has leading and trailing pipes; drop the empty edge columns. if (delim === '|' && rows.length && rows.every(function(r){ return r.length > 1 && r[0].trim() === '' && r[r.length-1].trim() === ''; })) { rows = rows.map(function(r){ return r.slice(1, -1); }); rows = rows.filter(function(r){ return !r.every(function(c){ return /^\s*:?-+:?\s*$/.test(c); }); }); } if (trim) rows = rows.map(function(r){ return r.map(function(c){ return c.trim(); }); }); if (!rows.length) { _ctCsvMdLast = { rows: [], aligns: [], header: header }; _ctCsvMdRenderPreview(); if (status) status.textContent = ''; return ''; } var width = 0; rows.forEach(function(r){ if (r.length > width) width = r.length; }); rows = rows.map(function(r){ r = r.slice(); while (r.length < width) r.push(''); return r; }); var head = header ? rows[0] : rows[0].map(function(){ return ''; }); var body = header ? rows.slice(1) : rows; var aligns = []; for (var c = 0; c < width; c++) { if (align === 'auto') { var vals = body.map(function(r){ return r[c].trim(); }).filter(function(v){ return v !== ''; }); aligns.push(vals.length && vals.every(_ctIsNumber) ? 'right' : ''); } else { aligns.push(align === 'none' ? '' : align); } } var cells = [head].concat(body).map(function(r){ return r.map(_ctMdEscape); }); var widths = []; for (var c = 0; c < width; c++) { var w = 3; if (pad) cells.forEach(function(r){ var cw = _ctCellWidth(r[c]); if (cw > w) w = cw; }); widths.push(w); } function padCell(s, c) { if (!pad) return s; var gap = widths[c] - _ctCellWidth(s); if (gap <= 0) return s; if (aligns[c] === 'right') return ' '.repeat(gap) + s; if (aligns[c] === 'center') { var l = Math.floor(gap / 2); return ' '.repeat(l) + s + ' '.repeat(gap - l); } return s + ' '.repeat(gap); } function line(r) { return '| ' + r.map(padCell).join(' | ') + ' |'; } var sep = '| ' + widths.map(function(w, c){ var a = aligns[c]; var n = pad ? w : 3; if (a === 'left') return ':' + '-'.repeat(n - 1); if (a === 'right') return '-'.repeat(n - 1) + ':'; if (a === 'center') return ':' + '-'.repeat(Math.max(1, n - 2)) + ':'; return '-'.repeat(n); }).join(' | ') + ' |'; var out = [line(cells[0]), sep].concat(cells.slice(1).map(line)).join('\n'); _ctCsvMdLast = { rows: [head].concat(body), aligns: aligns, header: header }; _ctCsvMdRenderPreview(); if (status) { var names = { '\t': 'tab', ',': 'comma', ';': 'semicolon', '|': 'pipe' }; status.textContent = (delimChoice === 'auto' ? 'Detected ' + names[delim] + ' separated. ' : '') + width + ' column' + (width === 1 ? '' : 's') + ', ' + body.length + ' row' + (body.length === 1 ? '' : 's'); } return out; } function _ctCsvMdRenderPreview() { var wrap = document.getElementById('csvmd-preview'); if (!wrap) return; var d = _ctCsvMdLast; if (!d.rows.length) { wrap.style.display = 'none'; wrap.innerHTML = ''; return; } function esc(s) { return String(s).replace(/[&<>]/g, function(ch){ return ({'&':'&','<':'<','>':'>'})[ch]; }).replace(/\n/g, '
'); } function cell(tag, s, c) { var a = d.aligns[c] ? ' style=\"text-align:' + d.aligns[c] + '\"' : ''; return '<' + tag + a + '>' + esc(s) + ''; } var html = '
Preview
'; html += d.rows[0].map(function(s, c){ return cell('th', s, c); }).join(''); html += ''; var shown = d.rows.slice(1, 201); shown.forEach(function(r){ html += '' + r.map(function(s, c){ return cell('td', s, c); }).join('') + ''; }); html += '
'; if (d.rows.length > 201) html += '
Showing the first 200 rows. The Markdown above has all ' + (d.rows.length - 1) + '.
'; wrap.innerHTML = html; wrap.style.display = ''; } $(function(){ $('#csvmd-open').on('click', function(){ $('#csvmd-file').val('').trigger('click'); }); $('#csvmd-file').on('change', function(){ var f = this.files && this.files[0]; if (!f) return; var reader = new FileReader(); reader.onload = function(){ // texttotext.js listens natively; jQuery's trigger() would not reach it. var box1 = document.getElementById('box1'); box1.value = reader.result; box1.dispatchEvent(new Event('keyup', { bubbles: true })); }; reader.readAsText(f); }); $('#csvmd-download').on('click', function(){ var md = $('#box2').val(); if (!md) { alert('Paste some CSV in the box first.'); return; } var a = document.createElement('a'); a.href = URL.createObjectURL(new Blob([md + '\n'], { type: 'text/markdown;charset=utf-8' })); a.download = 'table.md'; document.body.appendChild(a); a.click(); setTimeout(function(){ URL.revokeObjectURL(a.href); a.remove(); }, 1000); }); setTimeout(function(){ var box1 = document.getElementById('box1'); if (box1 && box1.value) box1.dispatchEvent(new Event('keyup', { bubbles: true })); }, 50); }); var _loadedScripts = {}; function loadScriptPromise(url) { if (_loadedScripts[url]) return _loadedScripts[url]; _loadedScripts[url] = new Promise(function (resolve, reject) { var s = document.createElement('script'); s.src = url; s.onload = resolve; s.onerror = reject; document.head.appendChild(s); }); return _loadedScripts[url]; } function replaceAll(find, replace, str) { return str.replace(new RegExp(find, 'g'), replace); } function beautify(str) { var result = ''; var length = str.length; var i = 0; var braceCountLeft = 0; var braceCountRight = 0; var withinQuotes = false; while (i < length) { var c = str[i]; if (c == '"' && (i == 0 || c[i - 1] != '\\')) { // non-escaped quotes withinQuotes = !withinQuotes; } if (!withinQuotes && (c == '}' || c == '{' || c == ',')) { console.log('Start####' + result); // look back and remove carriage returns and whitespace that are already there var resultIndex = result.length - 1; while (resultIndex >= 0 && (result[resultIndex] == ' ' || result[resultIndex] == '\r' || result[resultIndex] == '\n' || result[resultIndex] == '\t')) { resultIndex = resultIndex - 1; result = result.substr(0, resultIndex + 1); console.log('char ' + result[resultIndex] + '-----' + result + 'zzz ' + result.length + ' ' + resultIndex); } if (c == '{') { braceCountLeft++; result += c + '\r' + GetTabs(braceCountLeft - braceCountRight); } else if (c == '}') { braceCountRight++; // precede with carriage return result += '\r' + GetTabs(braceCountLeft - braceCountRight) + c; } else if (c == ',') { result += c + '\r' + GetTabs(braceCountLeft - braceCountRight); } var nextChar = ''; // advance through whitespace and remove carriage returns that are already there while (i < length && (str[i + 1] == ' ' || str[i + 1] == '\r' || str[i + 1] == '\n' || str[i + 1] == '\t')) { i++; } } else { result += str[i]; } i++; } return result; } function GetTabs(count) { var result = ''; for (var i = 0; i < count; i++) { result += ' '; } return result; }